/*
  ivl_base.c  -  implementation of fundamental interval functions

  This file is part of the IVL Library (LIBIVL).
  
  LIBIVL - library for interval computations 
  
  Copyright (c) 2007 Mateusz Paprocki

  The IVL Library is free software; you can redistribute it and/or modify
  it under the terms of the GNU Lesser General Public License as published
  by the Free Software Foundation; either version 2.1 of the License, or
  (at your option) any later version.

  The IVL Library is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  License for more details.

  You should have received a copy of the GNU Lesser General Public License
  along with the IVL Library; see the file LICENCE.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#include "interval.h"

void ivl_init(ivl_ptr ivl) {
	mpfr_init(IVL_LEFT(ivl));
	mpfr_init(IVL_RIGHT(ivl));		
	ivl->domain = IVL_UNDEFINED;
}

void ivl_init2(ivl_ptr ivl, mp_prec_t prec) {
	mpfr_init2(IVL_LEFT(ivl), prec);
	mpfr_init2(IVL_RIGHT(ivl), prec);
	ivl->domain = IVL_UNDEFINED;
}

void ivl_clear(ivl_ptr ivl) {
	mpfr_clear(IVL_LEFT(ivl));
	mpfr_clear(IVL_RIGHT(ivl));
	ivl->domain = IVL_UNDEFINED;	
}

void ivl_swap(ivl_ptr x, ivl_ptr y) {
	ivl_domain_t domain;
	
	mpfr_swap(IVL_LEFT(x), IVL_LEFT(y));
	mpfr_swap(IVL_RIGHT(x), IVL_RIGHT(y));
	
	domain = x->domain;
	x->domain = y->domain;
	y->domain = domain;
}

void ivl_set_prec(ivl_ptr ivl, mp_prec_t prec) {
	mpfr_set_prec(IVL_LEFT(ivl), prec);
	mpfr_set_prec(IVL_RIGHT(ivl), prec);	
	ivl->domain = IVL_UNDEFINED;
}

mp_prec_t ivl_get_prec(ivl_srcptr ivl) {
	mp_prec_t left_prec, right_prec;
	
	left_prec = mpfr_get_prec(IVL_LEFT(ivl));
	right_prec = mpfr_get_prec(IVL_RIGHT(ivl));
	
	return (left_prec <= right_prec) ? left_prec : right_prec;
}

int ivl_set_domain(ivl_ptr ivl, ivl_domain_t dom) {
	if ((dom != IVL_UNDEFINED) && IVL_NAN_P(ivl))
		return 0;
	else {
		ivl->domain = dom;
		return 1;
	}
}

ivl_domain_t ivl_get_domain(ivl_srcptr ivl) {
	return ivl->domain;
}

int ivl_get_left(mpfr_ptr fr, ivl_srcptr ivl) {
	return mpfr_set(fr, IVL_LEFT(ivl), GMP_RNDD);
}

int ivl_get_right(mpfr_ptr fr, ivl_srcptr ivl) {
	return mpfr_set(fr, IVL_RIGHT(ivl), GMP_RNDU);
}

double ivl_get_left_d(ivl_srcptr ivl) {
	return mpfr_get_d(IVL_LEFT(ivl), GMP_RNDD);
}

double ivl_get_right_d(ivl_srcptr ivl) {
	return mpfr_get_d(IVL_RIGHT(ivl), GMP_RNDU);
}

void ivl_print(FILE *fp, ivl_srcptr ivl, int base, size_t digits) {
	if (ivl->domain == IVL_UNDEFINED)
		fprintf(fp, "(NaN, NaN, False)\n");
	else {	
		fprintf(fp, "(");
		mpfr_out_str(fp, base, digits, IVL_LEFT(ivl), GMP_RNDD);
		fprintf(fp, ", ");
		mpfr_out_str(fp, base, digits, IVL_RIGHT(ivl), GMP_RNDU);
		
		fprintf(fp, ", %s)\n", ivl->domain == IVL_TOTAL ? "True" : "None");
	}
}

int ivl_length(mpfr_t len, ivl_srcptr ivl) {
	int inexact = 0;
	
	if (DOM_UNDEFINED(ivl))
		mpfr_set_nan(len);
	else {
		inexact = mpfr_sub(len, IVL_RIGHT(ivl), IVL_LEFT(ivl), GMP_RNDU); 
		mpfr_abs(len, len, GMP_RNDU);
	}
	
	return inexact;
}

int ivl_has_zero(ivl_srcptr ivl) {
	if (DOM_UNDEFINED(ivl))
		return 0;
	else
		return (mpfr_sgn(IVL_RIGHT(ivl)) >= 0) && (mpfr_sgn(IVL_LEFT(ivl)) < 0);		
}
 
int ivl_point_p(ivl_srcptr ivl) {
	if (DOM_UNDEFINED(ivl))
		return 0;
	else
		return mpfr_equal_p(IVL_LEFT(ivl), IVL_RIGHT(ivl));
}

int ivl_point_inf_p(ivl_srcptr ivl) {
	if (DOM_UNDEFINED(ivl))
		return 0;
	else
		return mpfr_inf_p(IVL_LEFT(ivl)) && mpfr_equal_p(IVL_LEFT(ivl), IVL_RIGHT(ivl));
}

int ivl_bounded_p(ivl_srcptr ivl) {
	if (DOM_UNDEFINED(ivl))
		return 0;
	else
		return (!mpfr_inf_p(IVL_LEFT(ivl))) && (!mpfr_inf_p(IVL_RIGHT(ivl)));
}

int ivl_unbounded_p(ivl_srcptr ivl) {
	if (DOM_UNDEFINED(ivl))
		return 0;
	else
		return (mpfr_sgn(IVL_LEFT(ivl)) != mpfr_sgn(IVL_RIGHT(ivl))) &&
		    	mpfr_inf_p(IVL_LEFT(ivl)) && mpfr_inf_p(IVL_RIGHT(ivl));  
}
